Amazon Athena で S3 Glacier の復元されたデータをクエリ可能とする構成を AWS CDK で構築してみた

Amazon Athena で S3 Glacier の復元されたデータをクエリ可能とする構成を AWS CDK で構築してみた

Clock Icon2024.12.26

こんにちは、製造ビジネステクノロジー部の若槻です。

前回の下記ブログで、ストレージクラスが S3 Glacier(Amazon S3 Glacier Flexible Retrieval または Amazon S3 Glacier Deep Archive)でアーカイブされたオブジェクトであっても、復元することにより Amazon Athena でクエリ可能であることをドキュメントベースで確認しました。

https://dev.classmethod.jp/articles/amazon-athena-amazon-s3-storage-class-query/

今回は、Amazon Athena で S3 Glacier の復元されたデータをクエリ可能とする構成を AWS CDK で構築し、実際に動作を確認してみました。

やってみた

初回環境構築(テーブルプロパティ未設定)

まずは初回環境構築として Athena ワークグループ、S3 バケット、Glue データベースおよびテーブルの作成を行います。ただしアーカイブから復元済みのオブジェクトをクエリ可能とするテーブルプロパティは比較検証のためここではまだ設定しません。

lib/main-stack.ts
import * as cdk from 'aws-cdk-lib';
import * as s3 from 'aws-cdk-lib/aws-s3';
import * as athena from 'aws-cdk-lib/aws-athena';
import * as glue_alpha from '@aws-cdk/aws-glue-alpha';
import { Construct } from 'constructs';

export class MainStack extends cdk.Stack {
  constructor(scope: Construct, id: string) {
    super(scope, id);

    /**
     * Ahena ワークグループ
     */
    new athena.CfnWorkGroup(this, 'WorkGroup', {
      name: 'workGroup',
    });

    /**
     * S3 バケット
     */
    const bucket = new s3.Bucket(this, 'Bucket');

    /**
     * Glue データベース
     */
    const database = new glue_alpha.Database(this, 'Database');

    /**
     * Glue テーブル
     */
    new glue_alpha.S3Table(this, 'S3Table', {
      database,
      bucket,
      dataFormat: glue_alpha.DataFormat.CSV,
      columns: [
        {
          name: 'storageClass',
          type: glue_alpha.Schema.STRING,
        },
      ],
    });

    // アーカイブから復元済みのオブジェクトをクエリ可能とするテーブルプロパティは未設定
  }
}

上記 CDK 実装をデプロイして環境を構築します。

アーカイブの復元

アーカイブされたオブジェクトを復元させます。

オブジェクトをストレージクラス Amazon S3 Glacier Flexible Retrieval でアップロードします。

aws s3api put-object \
    --bucket ${BUCKET_NAME} \
    --key "GLACIER.csv" \
    --body temp.csv \
    --content-type text/csv \
    --storage-class GLACIER

アップロードされたオブジェクトです。この時点では RestoreStatus プロパティが無いため、アーカイブされたオブジェクトであることがわかります。

$ aws s3api list-objects-v2 \
    --bucket ${BUCKET_NAME} \
    --optional-object-attributes="RestoreStatus"
{
    "Contents": [
        {
            "Key": "GLACIER.csv",
            "LastModified": "2024-12-24T12:47:38+00:00",
            "ETag": "\"5cfbeb7f21290d361ec2e49764b92852\"",
            "Size": 8,
            "StorageClass": "GLACIER"
        }
    ],
    "RequestCharged": null
}

アーカイブからの復元を開始します。今回は取り出しオプションで Expedited(迅速)を指定して 1〜5 分以内で復元を完了させるようにします。

aws s3api restore-object \
    --bucket ${BUCKET_NAME} \
    --key "GLACIER.csv" \
    --restore-request '{"Days":1,"GlacierJobParameters":{"Tier":"Expedited"}}'

復元開始直後のオブジェクトの状態を確認します。追加された RestoreStatus プロパティで "IsRestoreInProgress": true となっており、復元が進行中であることがわかります。

$ aws s3api list-objects-v2 \
    --bucket ${BUCKET_NAME} \
    --optional-object-attributes="RestoreStatus"
{
    "Contents": [
        {
            "Key": "GLACIER.csv",
            "LastModified": "2024-12-24T12:47:38+00:00",
            "ETag": "\"5cfbeb7f21290d361ec2e49764b92852\"",
            "Size": 8,
            "StorageClass": "GLACIER",
            "RestoreStatus": {
                "IsRestoreInProgress": true
            }
        }
    ],
    "RequestCharged": null
}

1,2分程待ってから再度確認すると、"IsRestoreInProgress": false となり、また RestoreExpiryDate が記録されて復元が完了していることがわかります。

$ aws s3api list-objects-v2 \
    --bucket ${BUCKET_NAME} \
    --optional-object-attributes="RestoreStatus"
{
    "Contents": [
        {
            "Key": "GLACIER.csv",
            "LastModified": "2024-12-24T12:47:38+00:00",
            "ETag": "\"5cfbeb7f21290d361ec2e49764b92852\"",
            "Size": 8,
            "StorageClass": "GLACIER",
            "RestoreStatus": {
                "IsRestoreInProgress": false,
                "RestoreExpiryDate": "2024-12-28T00:00:00+00:00"
            }
        }
    ],
    "RequestCharged": null
}

これでアーカイブされたオブジェクトを復元することができました。

参考

https://aws.amazon.com/jp/about-aws/whats-new/2023/06/amazon-s3-restore-status-s3-glacier-objects-list-api/
https://awscli.amazonaws.com/v2/documentation/api/latest/reference/s3api/list-objects-v2.html
https://dev.classmethod.jp/articles/amazon-s3-list-object-api-add-restored-status/
https://dev.classmethod.jp/articles/amazon-s3-glacier-flexible-retrieval-improves-restore-time/
https://docs.aws.amazon.com/ja_jp/AmazonS3/latest/userguide/restoring-objects-retrieval-options.html

テーブルプロパティ未設定の場合はクエリで取得できない

さてここで Amazon Athena からクエリを実行してみると、クエリでオブジェクト内のデータを取得することができませんでした。期待通りの挙動です。

テーブルプロパティを設定する

さて、続いて Athena で復元済みのオブジェクトをクエリできるようにはじめの構成を修正します。

必要な設定として、Glue テーブルのテーブルプロパティにエスケープハッチで 'read_restored_glacier_objects' = 'true' を追加します。

lib/main-stack.ts
import * as cdk from 'aws-cdk-lib';
import * as s3 from 'aws-cdk-lib/aws-s3';
import * as athena from 'aws-cdk-lib/aws-athena';
import * as glue from 'aws-cdk-lib/aws-glue';
import * as glue_alpha from '@aws-cdk/aws-glue-alpha';
import { Construct } from 'constructs';

export class MainStack extends cdk.Stack {
  constructor(scope: Construct, id: string) {
    super(scope, id);

    /**
     * Ahena ワークグループ
     */
    new athena.CfnWorkGroup(this, 'WorkGroup', {
      name: 'workGroup',
    });

    /**
     * S3 バケット
     */
    const bucket = new s3.Bucket(this, 'Bucket');

    /**
     * Glue データベース
     */
    const database = new glue_alpha.Database(this, 'Database');

    /**
     * Glue テーブル
     */
    const s3Table = new glue_alpha.S3Table(this, 'S3Table', {
      database,
      bucket,
      dataFormat: glue_alpha.DataFormat.CSV,
      columns: [
        {
          name: 'storageClass',
          type: glue_alpha.Schema.STRING,
        },
      ],
    });
    const cfnS3Table = s3Table.node.defaultChild as glue.CfnTable;

    /**
     * 復元された Glacier オブジェクトの読み取りを Glue テーブルに対して有効化
     */
    cfnS3Table.addPropertyOverride(
      'TableInput.Parameters.read_restored_glacier_objects',
      true
    );
  }
}

上記の修正済みコードを CDK デプロイして環境を更新します。

更新後に再度 Athena からクエリを実行してみると、復元済みのオブジェクト内のデータを取得することができました。

参考

https://aws.amazon.com/jp/about-aws/whats-new/2023/06/amazon-athena-querying-restored-data-s3-glacier/
https://dev.classmethod.jp/articles/querying-restored-glacier-objects-from-amazon-athena/
https://dev.classmethod.jp/articles/aws-cdk-typescript-how-to-set-properties-not-in-construct-props-in-high-level-construct/

復元有効期限に注意点

なお、アーカイブから復元したオブジェクトの復元有効期間に期限がある点には注意しましょう。デフォルトでは次のように 1 日 + 最初の GMT 0 時までの時間が復元有効期間となるようです。

$ aws s3api head-object \
    --bucket ${BUCKET_NAME} \
    --key "GLACIER.csv"
{
    "AcceptRanges": "bytes",
    "Restore": "ongoing-request=\"false\", expiry-date=\"Sat, 28 Dec 2024 00:00:00 GMT\"",
    "LastModified": "2024-12-24T12:47:38+00:00",
    "ContentLength": 8,
    "ETag": "\"5cfbeb7f21290d361ec2e49764b92852\"",
    "ContentType": "text/csv",
    "ServerSideEncryption": "AES256",
    "Metadata": {},
    "StorageClass": "GLACIER"
}

参考

https://docs.aws.amazon.com/ja_jp/AmazonS3/latest/userguide/restoring-objects.html

おわりに

Amazon Athena で S3 Glacier の復元されたデータをクエリ可能とする構成を AWS CDK で構築し、実際に動作を確認してみました。

コスト軽減のために S3 ライフサイクルポリシーでデータを Glacier にアーカイブするケースは多いと思います。その際にアーカイブされたデータを Athena などで分析したい場合は追加のテーブルプロパティ設定が必要となるので気をつけるようにしましょう。

以上

Share this article

facebook logohatena logotwitter logo

© Classmethod, Inc. All rights reserved.